﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.Windows.Threading;
using System.ServiceModel;
using System.ServiceModel.Discovery;
using System.ComponentModel;

namespace WindSim
{
    public abstract class BaseClient : Window, INotifyPropertyChanged
    {
        //Properties & Fields
        protected SimServiceReference.SimulationService _client;
        public SynchronizationContext _syncContext;

        public abstract string ClientName { get; set; }
        public abstract Guid ClientGuid { get; }
        public abstract SimServiceReference.ClientType ClientType { get; }

        protected string _searchServiceStatusMessage = "";
        protected string _searchServiceCaption = "Suche Dienst...";
        public virtual string SearchServiceStatusMessage
        {
            get { return _searchServiceStatusMessage; }
            set
            {
                _searchServiceStatusMessage = value;
                NotifyPropertyChanged("SearchServiceStatusMessage");
            }        
        }
        public virtual bool IsConnected {get; set; }
        public virtual bool IsSearching { get; set; }
        public string SearchServiceCaption 
        {
            get { return _searchServiceCaption; }
            set { _searchServiceCaption = value; NotifyPropertyChanged("SearchServiceCaption"); } 
        }

        //NotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        //InvokeAction
        protected void InvokeAction(Action action)
        {
            if (CheckAccess())
            {
                action();
            }
            else
            {
                Dispatcher.BeginInvoke(action, DispatcherPriority.Render);
            }
        }

        //Methods
        protected void DiscoverService()
        {
            IsSearching = true;
            IsConnected = false;
            SearchServiceStatusMessage = String.Empty;
            SearchServiceCaption = "Suche Dienst...";

            var discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
            discoveryClient.FindProgressChanged += discoveryClient_FindProgressChanged;
            discoveryClient.FindCompleted += discoveryClient_FindCompleted;
            FindCriteria findCriteria = new FindCriteria(typeof(SimServiceReference.SimulationService));
            findCriteria.Duration = TimeSpan.FromSeconds(2);
            discoveryClient.FindAsync(findCriteria);
        }
        protected void discoveryClient_FindProgressChanged(object sender, FindProgressChangedEventArgs e)
        {
            try
            {
                EndpointDiscoveryMetadata metadata = e.EndpointDiscoveryMetadata;
                SearchServiceStatusMessage = "Dienst gefunden: " + metadata.Address;
            }
            catch (Exception)
            {
                IsSearching = false;
                IsConnected = false;
            }
        }
        void discoveryClient_FindCompleted(object sender, FindCompletedEventArgs e)
        {
            try
            {
                FindResponse response = e.Result;
                _syncContext = SynchronizationContext.Current;
                InstanceContext callbackContext = new InstanceContext(this);
                _client = new SimServiceReference.SimulationServiceClient(callbackContext, "Tcp", response.Endpoints[0].Address);
                IsSearching = false;
                IsConnected = true;
                SearchServiceCaption = "Suche erfolgreich";
            }
            catch (Exception ex)
            {
                SearchServiceCaption = "Suche fehlgeschlagen";
                StringBuilder sb = new StringBuilder();
                sb.Append("Stellen Sie sicher, dass der WindSimServiceHost auf einem Computer erfolgreich gestartet wurde und dieser im Netzwerk erreichbar ist. ");
                sb.Append("Überprüfen Sie gegebenfalls auch Ihre Firewall-Einstellungen.");
                sb.AppendLine();
                sb.AppendLine();
                sb.AppendLine("Details:");

                if (ex is ArgumentOutOfRangeException)
                {
                    sb.AppendLine("Es konnte kein Host ermittelt werden, der den Dienst zur Verfügung stellt."); 
                }
                else
                {
                    sb.AppendLine(ex.GetType().ToString() + " - " + ex.Message);
                }

                SearchServiceStatusMessage = sb.ToString();
                IsSearching = false;
                IsConnected = false;
            }
        }
    }
}
